// TODO: CODE REVIEW & CLEANUP!
//
// MusicQueueScreen.xaml.cs
//

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Xml;
using HomeUX.ClientAppSupport;
using HomeUX.ClientControlSupport;
using HomeUX.Controls;
using HomeUX.Synchronization;
using HomeUX.Utilities;

namespace HomeUX.MusicClientLibrary
{

public partial class MusicQueueScreen : UserControl
{
    MusicClientHelper _musicClientHelper;
    SyncNode _albumIdNode; // "<device>\AlbumId" node
    SyncNode _trackNumberNode; // "<device>\TrackNumber" node

    SyncNode _queueSaveStateNode;

    Style _trackButtonGridStyle, _trackButtonTextStyle, _trackButtonSequenceBorderStyle,
        _trackButtonSequenceTextStyle;

    Mode _mode;
    
    List<TrackInfo> _queue = new List<TrackInfo>();

    /// <summary>
    /// During Mode.ReorderedTracks, this holds the current reordered queue.
    /// </summary>
    List<TrackInfo> _reorderedQueue = null;

    /// <summary>
    /// During Mode.ReorderedTracks, this holds the index into <r>_reorderedQueue</r> of the
    /// spot where the next chosen track will go.
    /// </summary>
    int _reorderedQueueIndex;

    SyncNode _queueChangeCountNode;

    /// <summary>
    /// A <n>String.Format</n>-style format string to use for <n>HeaderTextBlock</n>.  Initialized
    /// from the design-time text value of  <n>HeaderTextBlock</n>.
    /// </summary>
    string _headerFormatString;

    public MusicQueueScreen()
    {
        InitializeComponent();

        // initialize <_headerFormatString>
        _headerFormatString = HeaderTextBlock.Text;

        Loaded += MusicQueueScreen_Loaded;
        GotFocus += MusicQueueScreen_GotFocus;

    }

    void MusicQueueScreen_Loaded(object sender, RoutedEventArgs e)
    {
        _trackButtonGridStyle = (Style)LayoutRoot.Resources["TrackButtonGridStyle"];
        _trackButtonTextStyle = (Style)LayoutRoot.Resources["TrackButtonTextStyle"];
        _trackButtonSequenceBorderStyle = (Style)LayoutRoot.Resources["TrackButtonSequenceBorderStyle"];
        _trackButtonSequenceTextStyle = (Style)LayoutRoot.Resources["TrackButtonSequenceTextStyle"];

        _musicClientHelper = new MusicClientHelper(this, BeginLoadingDataFromMusicServer,
            OnParcelReceived);
        _musicClientHelper.LoadingMessage = "Loading queue...";
        _musicClientHelper.Screen.Opened += OnScreenOpened;

        ShuffleButton.SyncPath = _musicClientHelper.MusicDeviceName + @"\IsShuffleMode";
        RepeatButton.SyncPath = _musicClientHelper.MusicDeviceName + @"\IsLoopMode";
        
        _queueChangeCountNode = (SyncNode)_musicClientHelper.MusicDeviceNode.CreateNode(
            SyncPath.FromString("QueueChangeCount"));
        _queueChangeCountNode.ValueChanged += _queueChangeCountNode_ValueChanged;

        _albumIdNode = (SyncNode)_musicClientHelper.MusicDeviceNode.CreateNode(
            SyncPath.FromString("AlbumId"));
        _trackNumberNode = (SyncNode)_musicClientHelper.MusicDeviceNode.CreateNode(
            SyncPath.FromString("TrackNumber"));

        _albumIdNode.ValueChanged += OnCurrentTrackChangedAsync;
        _trackNumberNode.ValueChanged += OnCurrentTrackChangedAsync;

        _queueSaveStateNode = (SyncNode)_musicClientHelper.MusicDeviceNode.CreateNode(
            SyncPath.FromString("QueueSaveState"));
        _queueSaveStateNode.ValueChanged += delegate
        {
            OnQueueSaveStateChanged();
        };
        if (_queueSaveStateNode.Value != null)
            OnQueueSaveStateChanged();
    }

    void OnQueueSaveStateChanged()
    {
        QueueSaveState queueSaveState;
        string associatedPlaylistName;

        MusicQueueScreen.ParseQueueSaveState(_queueSaveStateNode, out queueSaveState,
			out associatedPlaylistName);

        QueueNewNotEmptyTextBlock.Visibility =
			ClientUtil.GetVisibility(queueSaveState == QueueSaveState.NewNotEmpty);
        QueueLoadedTextBlock.Visibility =
            ClientUtil.GetVisibility(queueSaveState == QueueSaveState.Loaded);
        QueueLoadedModifiedTextBlock.Visibility =
            ClientUtil.GetVisibility(queueSaveState == QueueSaveState.LoadedModified);
        QueueSavedTextBlock.Visibility =
            ClientUtil.GetVisibility(queueSaveState == QueueSaveState.Saved);
        QueueSavedModifiedTextBlock.Visibility =
            ClientUtil.GetVisibility(queueSaveState == QueueSaveState.SavedModified);

        if ((queueSaveState == QueueSaveState.NewEmpty) ||
            (queueSaveState == QueueSaveState.NewNotEmpty))
		{
            CurrentPlaylistNameTextBlock.Text = String.Empty;
            CurrentPlaylistNameTextBlock.Visibility = Visibility.Collapsed;
		}
		else
		{
            CurrentPlaylistNameTextBlock.Text = associatedPlaylistName;
            CurrentPlaylistNameTextBlock.Visibility = Visibility.Visible;
		}

        ForgetPlaylistButton.IsEnabled = (associatedPlaylistName != null);
    }

    void OnCurrentTrackChangedAsync(object sender, ValueChangedEventArgs e)
    {
        if (!_onCurrentTrackChangedPending)
        {
            _onCurrentTrackChangedPending = true;
            Dispatcher.BeginInvoke(OnCurrentTrackChanged);
        }
    }

    bool _onCurrentTrackChangedPending;

    TrackId _currentTrackId; // the currently-playing (or paused) track, or null if none

    void OnCurrentTrackChanged()
    {
        _onCurrentTrackChangedPending = false;

        if ((_albumIdNode.Value != null) && (_trackNumberNode.Value != null))
        {
            _currentTrackId = new TrackId()
            {
                AlbumId = (string)_albumIdNode.Value,
                TrackNumber = (int)_trackNumberNode.Value
            };
        }
        else
            _currentTrackId = null;

        GoToCurrentAlbum.IsEnabled = (_currentTrackId != null);

		UpdateHeader();
		UpdateSelection();
    }

    void OnScreenOpened(object sender, EventArgs e)
    {
        // do the same thing we'd do if we were waiting for the music server to become available
        _musicClientHelper.TryToLoadData();

        // reset state of GoToCurrentAlbum
        GoToCurrentAlbum.IsLit = false;
    }

    void BeginLoadingDataFromMusicServer()
    {
        RequestQueueDetails();
    }

    void _queueChangeCountNode_ValueChanged(object sender, ValueChangedEventArgs e)
    {
        // do nothing if we're in an error state
        if (_musicClientHelper.LoadState == MusicClientLoadState.Error)
            return;

        // the queue changed -- request details
        RequestQueueDetails();
    }

    void RequestQueueDetails()
    {
        string command = ParsedSyncNodeCommand.Format("GetQueueDetails",
            "RecipientId", XmlConvert.ToString(_musicClientHelper.RecipientId));
        _musicClientHelper.MusicDeviceNode.ExecuteCommand(command);
    }

    void OnParcelReceived(Guid recipientId, XmlReader reader)
    {
        // do nothing if we're in an error state
        if (_musicClientHelper.LoadState == MusicClientLoadState.Error)
            return;

        try
        {
            List<TrackInfo> newQueue = null;
            foreach (XmlElementInfo element in XmlElementInfo.EnumerateElements(reader))
            {
                switch (element.Name)
                {

                case "QueueDetails":

                    newQueue = new List<TrackInfo>();
                    break;

                case "TrackInQueue":

                    newQueue.Add(new TrackInfo()
                    {
                        TrackId = new TrackId()
                        {
                            AlbumId = element.GetRequiredAttribute("AlbumId"),
                            TrackNumber = element.GetRequiredIntAttribute("TrackNumber")
                        },
                        ArtistName = element.GetRequiredAttribute("ArtistName"),
                        AlbumName = element.GetRequiredAttribute("AlbumName"),
                        Name = element.GetRequiredAttribute("Name"),
                        Duration = element.GetRequiredDoubleAttribute("Duration"),
                    });
                    break;

                case "/QueueDetails":

                    // if we were in reorder-queue mode or delete-tracks mode, cancel that mode
                    if (_mode != Mode.Normal)
                        SwitchToMode(Mode.Normal);

                    //#warning Test code enabled!
                    //for (int i = 0; i < newQueue.Count; i++)
                    //    newQueue[i].Name = new String((char)('A' + i), 1);

                    _queue = newQueue;
                    OnQueueChanged();
                    _musicClientHelper.OnDataLoaded();
                    break;
                }
            }
        }
        catch (InvalidOperationException ex)
        {
            ClientGlobals.Alert(AlertType.Warning,
                "Invalid reply from server: {0}", ex.Message);
        }
    }

    // called when the queue changes
    void OnQueueChanged()
    {
		UpdateHeader();

        TracksListBox.Items.Clear();
        foreach (TrackInfo track in _queue)
        {
            track.Item = new Grid()
            {
                Tag = track,
                Style = _trackButtonGridStyle
            };
            track.Item.Children.Add(new TextBlock()
            {
                Style = _trackButtonTextStyle,
                Text = String.Format("[{0}] {1} - {2} - {3}",
                    Util.FormatDuration(track.Duration), track.Name, track.AlbumName,
                    track.ArtistName)
            });
            track.SequenceTextBlock = new TextBlock()
            {
                Style = _trackButtonSequenceTextStyle,
                Text = "0"
            };
            track.SequenceBorder = new Border()
            {
                Style = _trackButtonSequenceBorderStyle,
                Child = track.SequenceTextBlock
            };
            track.Item.Children.Add(track.SequenceBorder);
            TracksListBox.Items.Add(track.Item);
        }

        // enable/disable buttons that should be disabled when the queue is empty
        bool hasTracks = _queue.Count > 0;
        SaveQueueButton.IsEnabled = hasTracks;
        GoToAlbumModeButton.IsEnabled = hasTracks;
        ReorderTracksModeButton.IsEnabled = hasTracks;
        DeleteTracksModeButton.IsEnabled = hasTracks;

        _updateSelectionWhenLayoutIsComplete = true;
    }

    bool _updateSelectionWhenLayoutIsComplete;

    private void TracksListBox_LayoutComplete(object sender, EventArgs e)
    {
        if (_updateSelectionWhenLayoutIsComplete)
        {
            _updateSelectionWhenLayoutIsComplete = false;
            UpdateSelection();
        }
    }

    //void UpdateSelectionAsync()
    //{
    //    if (!_updateSelectionPending)
    //    {
    //        _updateSelectionPending = true;
    //        Dispatcher.BeginInvoke(UpdateSelection);
    //    }
    //}

    //bool _updateSelectionPending;


	void UpdateHeader()
	{
        double totalDuration = 0; // sum of track durations, in seconds
        int currentTrackIndex = -1;
        int trackIndex = 0;
        if (_currentTrackId != null)
        {
            foreach (TrackInfo track in _queue)
            {
                if (track.TrackId.Equals(_currentTrackId))
                    currentTrackIndex = trackIndex;
                totalDuration += track.Duration;
                trackIndex++;
            }
        }
        HeaderTextBlock.Text = String.Format(_headerFormatString,
            Util.FormatDuration(totalDuration), currentTrackIndex + 1, _queue.Count,
            _musicClientHelper.MusicDeviceName);
	}

    void UpdateSelection()
    {
        //_updateSelectionPending = false;

        int trackIndex = 0;
        foreach (TrackInfo track in
            ((_mode == Mode.ReorderTracks) ? (IEnumerable<TrackInfo>)_reorderedQueue : _queue))
        {
            TouchListBoxItem button;
            if (TracksListBox.TryMapItemToButton(track.Item, out button))
            {
                switch (_mode)
                {

                case Mode.Normal:

                    button.IsLit = track.TrackId.Equals(_currentTrackId);
                    if (button.IsLit)
                        TracksListBox.TrySetPseudofocus(button);
                    track.SequenceBorder.Visibility = Visibility.Collapsed;
                    break;

                case Mode.ReorderTracks:

                    button.IsLit = false;
                    if (trackIndex < _reorderedQueueIndex)
                    {
                        track.SequenceBorder.Visibility = Visibility.Visible;
                        track.SequenceTextBlock.Text = (trackIndex + 1).ToString();
                    }
                    else
                        track.SequenceBorder.Visibility = Visibility.Collapsed;
                    break;

                case Mode.DeleteTracks:

                    button.IsLit = track.WillDelete;
                    break;

                }
            }
            trackIndex++;
        }

        if (_mode == Mode.ReorderTracks)
            ReorderTracksUndoButton.IsEnabled = (_reorderedQueueIndex > 0);
    }

    void MusicQueueScreen_GotFocus(object sender, RoutedEventArgs e)
    {
        //TracksListBox.Focus();
    }

    private void TracksListBox_ItemClick(object sender, ItemClickEventArgs e)
    {
        TouchListBoxItem button;
        if (TracksListBox.TryMapItemToButton(e.Item, out button))
            TracksListBox.TrySetPseudofocus(button);

        var track = (TrackInfo)((Grid)e.Item).Tag;

        switch (_mode)
        {

        case Mode.Normal:

            // begin play starting from the clicked-on track
			string command = ParsedSyncNodeCommand.Format("PlayQueueItem",
				"TrackId", track.TrackId.ToString());

            button.IsWaiting = true;
            _musicClientHelper.WaitForMusicDeviceNode(delegate
            {
                button.IsWaiting = false;
            });

            _musicClientHelper.MusicDeviceNode.ExecuteCommand(command);

            // light up GoToCurrentAlbum to give the user the hint that this is the way to see the
            // album
            GoToCurrentAlbum.IsLit = true;
            break;

        case Mode.GoToAlbum:

            Screen screen;
            MusicAlbumScreen screenControl;
            _musicClientHelper.FindMusicScreen("Album", out screen, out screenControl);
            screenControl.AlbumId = track.TrackId.AlbumId;
            screenControl.HighlightTrackNumber = track.TrackId.TrackNumber;
            screen.GoTo();
            break;

        case Mode.ReorderTracks:

            int trackIndex = _reorderedQueue.IndexOf(track);
            if (trackIndex >= _reorderedQueueIndex)
            {
                // user clicked on a track that isn't part of the new sequence
                _reorderedQueue.RemoveAt(trackIndex);
                _reorderedQueue.Insert(_reorderedQueueIndex, track);
                _reorderedQueueIndex++;
            }
            else
            {
                // user clicked on a track that's already in <_reorderedQueue>
                _reorderedQueue.RemoveAt(trackIndex);
                _reorderedQueue.Insert(_reorderedQueueIndex - 1, track);
            }
            UpdateSelection();
            break;

        case Mode.DeleteTracks:

            track.WillDelete = !track.WillDelete;
            button.IsLit = track.WillDelete;
            break;
        }
    }

    void SwitchToMode(Mode newMode)
    {
		// update the mode switching UI
		string modeName;
        switch (newMode)
        {
        default:					modeName = "NormalMode"; break;
        case Mode.GoToAlbum:		modeName = "GoToAlbumMode"; break;
        case Mode.ReorderTracks:	modeName = "ReorderTracksMode"; break;
        case Mode.DeleteTracks:		modeName = "DeleteTracksMode"; break;
        }
		VisualStateManager.GoToState(this, modeName, true);

		// switch to the new mode
		_mode = newMode;
		switch (_mode)
		{
        default:
			break;
        case Mode.GoToAlbum:
			break;
        case Mode.ReorderTracks:
            _reorderedQueue = new List<TrackInfo>(_queue);
            _reorderedQueueIndex = 0;
			break;
        case Mode.DeleteTracks:
            foreach (TrackInfo track in _queue)
                track.WillDelete = false;
            break;
		}

        // update the selected state of track buttons
        UpdateSelection();
    }

    //TouchButton GetButtonOfMode(Mode mode)
    //{
    //    switch (mode)
    //    {
    //    case Mode.Normal: return null;
    //    case Mode.GoToAlbum: return GoToAlbumModeButton;
    //    case Mode.ReorderTracks: return ReorderTracksModeButton;
    //    case Mode.DeleteTracks: return DeleteTracksModeButton;
    //    }
    //}

    private void GoToAlbumModeButton_Click(object sender, RoutedEventArgs e)
    {
        if (_mode != Mode.GoToAlbum)
            SwitchToMode(Mode.GoToAlbum);
        else
            SwitchToMode(Mode.Normal);
    }

    private void ReorderTracksModeButton_Click(object sender, RoutedEventArgs e)
    {
        if (_mode != Mode.ReorderTracks)
            SwitchToMode(Mode.ReorderTracks);
        else
            SwitchToMode(Mode.Normal);
    }

    private void DeleteTracksModeButton_Click(object sender, RoutedEventArgs e)
    {
        if (_mode != Mode.DeleteTracks)
            SwitchToMode(Mode.DeleteTracks);
        else
            SwitchToMode(Mode.Normal);
    }

    private void GoToAlbumCancelButton_Click(object sender, RoutedEventArgs e)
    {
        SwitchToMode(Mode.Normal);
    }

    private void ReorderTracksUndoButton_Click(object sender, RoutedEventArgs e)
    {
        // Example of progression of <_reorderedQueue>
        // Index:     0 1 2 3 4 5 6
        // Initially: A B C D E F G -- same as <_queue>
        // Click "C": C A B D E F G
        // Click "F": C F A B D E G
        //                ^_reorderedQueueIndex

        // using the example above 
        TrackInfo trackF = _reorderedQueue[_reorderedQueueIndex - 1];
        _reorderedQueue.RemoveAt(_reorderedQueueIndex - 1); // remove F -- now have: C A B D E G
        int trackFOriginalIndex = _queue.IndexOf(trackF); // 5 in this example
        _reorderedQueue.Insert(trackFOriginalIndex, trackF); // reinsert F
        _reorderedQueueIndex--;
        UpdateSelection();
    }

    private void ReorderTracksOkButton_Click(object sender, RoutedEventArgs e)
    {
        var trackList = new StringBuilder();
        foreach (TrackInfo track in _reorderedQueue)
            ParsedSyncNodeCommand.FormatStringListItem(trackList, track.TrackId.ToString());

		string command = ParsedSyncNodeCommand.Format("ChangeQueue",
			"TrackIds", trackList.ToString());

        ReorderTracksOkButton.IsWaiting = true;
        _musicClientHelper.WaitForMusicDeviceNode(delegate
        {
            ReorderTracksOkButton.IsWaiting = false;
            SwitchToMode(Mode.Normal);
        });

        _musicClientHelper.MusicDeviceNode.ExecuteCommand(command);
    }

    private void ReorderTracksCancelButton_Click(object sender, RoutedEventArgs e)
    {
        SwitchToMode(Mode.Normal);
    }

    private void DeleteTracksSelectAllButton_Click(object sender, RoutedEventArgs e)
    {
        foreach (TrackInfo track in _queue)
            track.WillDelete = true;
        UpdateSelection();
    }

    private void DeleteTracksOkButton_Click(object sender, RoutedEventArgs e)
    {
        // set <trackList> to be the list of tracks to deleted
        var trackList = new StringBuilder();
        foreach (TrackInfo track in _queue)
        {
            if (track.WillDelete)
                ParsedSyncNodeCommand.FormatStringListItem(trackList, track.TrackId.ToString());
        }

        if (trackList.Length == 0)
        {
            SwitchToMode(Mode.Normal);
            if (_queue.Count == 0)
                PromptToDeletePlaylist();
            else
                TouchMessageBox.Show(this, "You didn't select any tracks to delete", "OK", null);
            return;
        }

        // set <command> to be a command that deletes from the queue those tracks in
        // <trackList>
        string command = ParsedSyncNodeCommand.Format("RemoveFromQueueMultipleAlbums",
            "TrackIds", trackList.ToString());

        DeleteTracksOkButton.IsWaiting = true;
        _musicClientHelper.WaitForMusicDeviceNode(delegate
        {
            DeleteTracksOkButton.IsWaiting = false;
			SwitchToMode(Mode.Normal);
            if (_queue.Count == 0)
                PromptToDeletePlaylist();
        });

        _musicClientHelper.MusicDeviceNode.ExecuteCommand(command);
    }

    private void DeleteTracksCancelButton_Click(object sender, RoutedEventArgs e)
    {
        SwitchToMode(Mode.Normal);
    }

    // TODO: move to "internal" section (used by other screens):
    static internal void ParseQueueSaveState(SyncNode queueSaveStateNode,
        out QueueSaveState queueSaveState, out string associatedPlaylistName)
    {
        string stringValue = queueSaveStateNode.Value as string;
        int colonIndex;
        if ((stringValue == null) || ((colonIndex = stringValue.IndexOf(':')) < 0))
        {
            queueSaveState = QueueSaveState.NewEmpty;
            associatedPlaylistName = null;
            return;
        }

        string queueSaveStateString = stringValue.Substring(0, colonIndex);
        switch (queueSaveStateString)
        {
            case "Loaded":
                queueSaveState = QueueSaveState.Loaded;
                break;
            case "LoadedModified":
                queueSaveState = QueueSaveState.LoadedModified;
                break;
            case "Saved":
                queueSaveState = QueueSaveState.Saved;
                break;
            case "SavedModified":
                queueSaveState = QueueSaveState.SavedModified;
                break;
            case "NewEmpty":
            default:
                queueSaveState = QueueSaveState.NewEmpty;
                break;
            case "NewNotEmpty":
                queueSaveState = QueueSaveState.NewNotEmpty;
                break;
        }

        associatedPlaylistName = stringValue.Substring(colonIndex + 1).Trim();
        if (associatedPlaylistName.Length == 0)
            associatedPlaylistName = null;
    }


    [DebuggerDisplay("{Name} - {AlbumName} - {ArtistName}")]
    class TrackInfo
    {
        public Grid Item; // the contents of the track's button in TracksListBox
        public Border SequenceBorder; // contains <SequenceTextBlock>
        public TextBlock SequenceTextBlock; // holds the sequence number during reordering
        //public string AlbumId;
        //public int TrackNumber;
        public TrackId TrackId;
        public string ArtistName;
        public string AlbumName;
        public string Name;
        public double Duration;

        public bool WillDelete; // used during Mode.DeleteTracks
    }

    public class TrackId
    {
        public string AlbumId;
        public int TrackNumber;

        public override bool Equals(object obj)
        {
            TrackId other = obj as TrackId;
            if (other == null)
                return false;
            return (AlbumId == other.AlbumId) && (TrackNumber == other.TrackNumber);
        }
        public override int GetHashCode()
        {
            return AlbumId.GetHashCode() ^ TrackNumber.GetHashCode();
        }

        // note that if the returned string is used as an argument
        // for ParsedSyncNodeCommand.Format then when the value is parsed by the
        // recipient of the command the *last* occurrence of ":" should be searched for
        public override string ToString()
		{
			return String.Format("{0}:{1}", AlbumId, TrackNumber);
		}
    }

    enum Mode
    {
        /// <summary>
        /// Clicking a track causes it to play.
        /// </summary>
        Normal,

        /// <summary>
        /// Clicking a track goes to the album containing that track.
        /// </summary>
        GoToAlbum,

        /// <summary>
        /// Clicking a track makes it the next one in the new track order.
        /// </summary>
        ReorderTracks,

        /// <summary>
        /// Clicking a track adds it to the collection of tracks to be deleted.
        /// </summary>
        DeleteTracks
    }

    private void GoToCurrentAlbum_Click(object sender, RoutedEventArgs e)
    {
        if (_currentTrackId != null)
        {
            Screen screen;
            MusicAlbumScreen screenControl;
            _musicClientHelper.FindMusicScreen("Album", out screen, out screenControl);
            screenControl.AlbumId = _currentTrackId.AlbumId;
            screenControl.HighlightTrackNumber = -1;
            screen.GoTo();
        }
    }

    private void LoadPlaylistButton_Click(object sender, RoutedEventArgs e)
    {
        _musicClientHelper.GoToMusicScreen("Load Playlist");
    }

    private void SaveQueueButton_Click(object sender, RoutedEventArgs e)
    {
        _musicClientHelper.GoToMusicScreen("Save Queue");
    }

    private void ForgetPlaylistButton_Click(object sender, RoutedEventArgs e)
    {
        // this could be implemented by setting SyncPath on the button, except for one thing: we
        // need to enable/disable the button based on conditions other than the availability of
        // the music server

        ForgetPlaylistButton.IsWaiting = true;
        _musicClientHelper.WaitForMusicDeviceNode(delegate
        {
            ForgetPlaylistButton.IsWaiting = false;
        });

        _musicClientHelper.MusicDeviceNode.ExecuteCommand("ForgetPlaylist");
    }

    private void PromptToDeletePlaylist()
    {
        QueueSaveState queueSaveState;
        string associatedPlaylistName;
        MusicQueueScreen.ParseQueueSaveState(_queueSaveStateNode, out queueSaveState,
			out associatedPlaylistName);

        if (!String.IsNullOrEmpty(associatedPlaylistName))
        {
            TouchMessageBox.Show(this,
                String.Format("The queue is now empty.\n\nWould you like to delete the playlist named \"{0}\"?\n\nNOTE: The playlist will be permanently deleted.",
                associatedPlaylistName), "Delete Playlist on Server|Cancel", delegate(int buttonIndex)
                {
                    if (buttonIndex == 0)
                        DeletePlaylist(associatedPlaylistName);
                });
        }
    }

    void DeletePlaylist(string playlistName)
    {
		string command = ParsedSyncNodeCommand.Format("DeletePlaylist",
			"PlaylistName", playlistName);

        DeleteTracksOkButton.IsWaiting = true;
        _musicClientHelper.WaitForMusicDeviceNode(delegate
        {
            DeleteTracksOkButton.IsWaiting = false;
        });

        _musicClientHelper.MusicDeviceNode.ExecuteCommand(command);
    }
}

internal enum QueueSaveState
{
    /// <summary>
    /// The queue is new (i.e. not associated with a playlist) and is empty.
    /// </summary>
    NewEmpty,

    /// <summary>
    /// The queue is new (i.e. not associated with a playlist) is not empty.
    /// </summary>
    NewNotEmpty,

    /// <summary>
    /// Queue was loaded from playlist <s>MusicPlayerDriver._queuePlaylistName</s>, and the queue
    /// has not been modified since then.
    /// </summary>
    Loaded,

    /// <summary>
    /// The queue was loaded from playlist <s>MusicPlayerDriver._queuePlaylistName</s>, and the queue
    /// has been modified since then.
    /// </summary>
    LoadedModified,

    /// <summary>
    /// The queue was was saved to playlist <s>MusicPlayerDriver._queuePlaylistName</s>, and the queue
    /// has not been modified since then.
    /// </summary>
    Saved,

    /// <summary>
    /// The queue was was saved to playlist <s>MusicPlayerDriver._queuePlaylistName</s>, and the queue
    /// has been modified since then.
    /// </summary>
    SavedModified
}

}
